
import java.awt.Graphics2D;
import java.util.LinkedList;
import mhv.fr.sprite.Sprite;
import mhv.fr.sprite.animator.SpriteAnimator;
import mhv.fr.sprite.container.SpriteContainer;

/*************************************************
 * JCENTIPEDE
 * by Marc-Henri Vuillaume
 * Centipede class
 *************************************************/
/**
 *
 * @author Marc-Henri
 */
public class Centipede {

    public enum CentipedeStatus {

        RIGHT, LEFT, UP, DOWN
    };
    static double CENTIPEDSPEED = 2.0;
    static int CENTIPEDELTSIZE = 18;
    static int CENTIPEDELTRADIUS = 9;
    static int SCREENWIDTH = 800;
    static int SCREENHEIGHT = 600;
    static int MUSHROOMSIZE = 32;
    final int SPRITE_MUSHROOM_NORMAL = 10;
    final int SPRITE_MUSHROOM_HIT_2 = 12;
    final int SPRITE_CENTIPEDE_HEAD = 20;
    final int SPRITE_CENTIPED_BODY = 21;
    private CentipedeStatus hStatus;
    private CentipedeStatus vStatus;
    private long centipedeId;
    private LinkedList<Long> entityList;
    private long mushroomIdHit;
    private boolean hitByMushroom;

    public long getCentipedeId() {
        return centipedeId;
    }

    public void setCentipedeId(long centipedeId) {
        this.centipedeId = centipedeId;
    }

    public LinkedList<Long> getEntityList() {
        return entityList;
    }

    public Sprite CreateElement(double x, double y, Graphics2D g2d) {
        Sprite sp = new Sprite(g2d);

        sp.setX(x);
        sp.setY(y);

        if (entityList.isEmpty()) {
            CentipedeHeadController ct = new CentipedeHeadController();
            sp.setNextX(x);
            sp.setNextY(y);
            ct.setCentipedeId(centipedeId);
            sp.setController(ct);
            sp.setType(SPRITE_CENTIPEDE_HEAD);
        } else {
            CentipedeBodyController ct = new CentipedeBodyController();
            sp.setNextX(x);
            sp.setNextY(y);
            ct.setCentipedeId(centipedeId);
            sp.setController(ct);
            sp.setType(SPRITE_CENTIPED_BODY);
        }
        entityList.add(SpriteContainer.getInstance().add(sp));

        return sp;
    }

    public CentipedeStatus getHStatus() {
        return hStatus;
    }

    public void setHStatus(CentipedeStatus hStatus) {
        this.hStatus = hStatus;
    }

    public CentipedeStatus getVStatus() {
        return vStatus;
    }

    public void setVStatus(CentipedeStatus vStatus) {
        this.vStatus = vStatus;
    }

    public void move() {
        double x, y, nx, ny;

        for (int i = 0; i < entityList.size(); i++) {
            Sprite sp = SpriteContainer.getInstance().getSprite(entityList.get(i));
            x = sp.getX();
            y = sp.getY();
            nx = sp.getNextX();
            ny = sp.getNextY();

            if (Math.abs(x - nx) < CENTIPEDSPEED) {
                sp.setX(nx);
            }
            if (Math.abs(y - ny) < CENTIPEDSPEED) {
                sp.setNextY(ny);
            }

            sp.setVelX(0);
            sp.setVelY(0);


            if (x > nx) {
                sp.setVelX(-CENTIPEDSPEED);
                sp.setFaceRotation(0);
            } else if (x < nx) {
                sp.setVelX(CENTIPEDSPEED);
                sp.setFaceRotation(180);
            }

            if (y > ny) {
                sp.setVelY(-CENTIPEDSPEED);
                sp.setFaceRotation(90);
            } else if (y < ny) {
                sp.setVelY(CENTIPEDSPEED);
                sp.setFaceRotation(270);
            }
            sp.updateMove();
        }
    }

    private void calculateNextMove() {
        Sprite sp = SpriteContainer.getInstance().getSprite(entityList.get(0));
        double x = sp.getX();
        double y = sp.getY();

        if (hStatus == CentipedeStatus.RIGHT) {
            x = x + CENTIPEDELTSIZE;
        } else {
            x = x - CENTIPEDELTSIZE;
        }
        //check collisions
        if ((x < 5) || (x > SCREENWIDTH - CENTIPEDELTRADIUS) || hitByMushroom) {
            x = sp.getX();
            //update vertical move
            if (vStatus == CentipedeStatus.DOWN) {
                if (y > SCREENHEIGHT - 10) {
                    addNewCentiped(Math.round(x / SCREENWIDTH) * SCREENWIDTH, SCREENHEIGHT / 2 + 10, sp.getGraphics());
                    setVStatus(CentipedeStatus.UP);
                } else {
                    y = y + CENTIPEDELTSIZE;
                }
            } else {
                if (y < SCREENHEIGHT / 2 + 10) {
                    addNewCentiped(Math.round(x / SCREENWIDTH) * SCREENWIDTH, SCREENHEIGHT -10, sp.getGraphics());
                    setVStatus(CentipedeStatus.DOWN);
                } else {
                    y = y - CENTIPEDELTSIZE;
                }
            }
            //toogle horizontal status
            if (hStatus == CentipedeStatus.RIGHT) {
                setHStatus(CentipedeStatus.LEFT);
            } else {
                setHStatus(CentipedeStatus.RIGHT);
            }
        }

        sp.setNextX(x);
        sp.setNextY(y);

        //update centiped
        SpriteContainer sc = SpriteContainer.getInstance();
        for (int i = 1; i < entityList.size(); i++) {
            sc.getSprite(entityList.get(i)).setX(sc.getSprite(entityList.get(i)).getNextX());
            sc.getSprite(entityList.get(i)).setY(sc.getSprite(entityList.get(i)).getNextY());
            sc.getSprite(entityList.get(i)).setNextX(sc.getSprite(entityList.get(i - 1)).getX());
            sc.getSprite(entityList.get(i)).setNextY(sc.getSprite(entityList.get(i - 1)).getY());
        }

    }

    public void CalculateNextMoveByHit(long mushRoomId) {
        if (mushroomIdHit != mushRoomId) {
            hitByMushroom = true;
            mushroomIdHit = mushRoomId;
            calculateNextMove();
        } else {
            hitByMushroom = false;
        }
    }

    public void CalculateNextMove() {

        hitByMushroom = false;
        mushroomIdHit = 0;
        calculateNextMove();
    }

    public int getSize() {
        return entityList.size();
    }

    public void DeleteHead() {
        SpriteContainer sc = SpriteContainer.getInstance();
        Sprite sp = sc.getSprite(entityList.get(0));
        //change head to mushroom;
        AddMushroom(sp);
        sc.delete(entityList.get(0));
        entityList.removeFirst();
        //change next element to head;
        if (entityList.size() > 0) {
            updateSpriteToHead(sc.getSprite(entityList.get(0)));
        }
    }

    public void SplitCentipede(long spId) {
        int index = 1;
        //find index of split
        for (int i = 1; i < entityList.size(); i++) {
            if (entityList.get(i) == spId) {
                index = i;
            }
        }
        AddMushroom(SpriteContainer.getInstance().getSprite(spId));
        SpriteContainer.getInstance().delete(spId);
        entityList.remove(index);
        //if index is not the centipede end
        if (index < entityList.size()) {
            Centipede cp = GameManager.getInstance().CreateCentipede();
            SpriteContainer sc = SpriteContainer.getInstance();

            for (int i = index; i < entityList.size(); i++) {
                SpriteAnimator anim = new SpriteAnimator();
                Sprite oldSp = sc.getSprite(entityList.get(i));
                Sprite sp = cp.CreateElement(oldSp.getX(), oldSp.getY(), oldSp.getGraphics());
                sp.setNextX(oldSp.getNextX());
                sp.setNextY(oldSp.getNextY());
                if (i == index) {
                    anim.load("Images/head.png", 4, 1, 22, 21);
                } else {
                    anim.load("Images/body.png", 4, 1, 18, 21);
                }
                anim.setFrameDelay(5);
                sp.setAnimator(anim);
                sp.setAlive(true);
                sc.delete(oldSp.getController().getSpriteId());
                entityList.remove(i);
                cp.setHStatus(hStatus);
                cp.setVStatus(vStatus);
            }
        }

    }

    private void AddMushroom(Sprite sp) {
        double x = sp.getX();
        double y = sp.getY();
        x = Math.round((x - MUSHROOMSIZE / 2) / MUSHROOMSIZE) * MUSHROOMSIZE + MUSHROOMSIZE / 2;
        y = Math.round((y - MUSHROOMSIZE / 2) / MUSHROOMSIZE) * MUSHROOMSIZE + MUSHROOMSIZE / 2;
        Sprite nsp = new Sprite(sp.getGraphics());
        nsp.setX(x);
        nsp.setY(y);
        nsp.setType(SPRITE_MUSHROOM_NORMAL);
        nsp.setController(new MushroomController());
        nsp.loadImage("Images/mush_normal.png");
        nsp.setAlive(true);
        SpriteContainer.getInstance().add(nsp);
    }

    private void updateSpriteToHead(Sprite sp) {
        CentipedeHeadController ct = new CentipedeHeadController();
        ct.setCentipedeId(centipedeId);
        sp.setController(ct);
        SpriteAnimator anim;
        anim = new SpriteAnimator();
        sp.setType(SPRITE_CENTIPEDE_HEAD);
        anim.load("Images/head.png", 4, 1, 22, 21);
        sp.setAnimator(anim);
        sp.setAlive(true);
    }

    private void addNewCentiped(double x, double y, Graphics2D g2d) {
        Centipede cp = GameManager.getInstance().CreateCentipede();
        SpriteContainer sc = SpriteContainer.getInstance();
        SpriteAnimator anim = new SpriteAnimator();
        Sprite sp = cp.CreateElement(x, y, g2d);
        sp.setNextX(x);
        sp.setNextY(y);
        anim.load("Images/head.png", 4, 1, 22, 21);
        anim.setFrameDelay(5);
        sp.setAnimator(anim);
        sp.setAlive(true);
        cp.setHStatus(hStatus);
        cp.setVStatus(vStatus);
    }

    public Centipede() {
        entityList = new LinkedList<Long>();
        centipedeId = 0;
        mushroomIdHit = 0;

    }
}
